package com.canyou.utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;

import java.util.concurrent.*;

/**
 * 延时任务工具类
 *
 * @author fy
 * @date 20/06/29 14:51
 */
@Slf4j
public final class DelayUtils {

    private DelayUtils() {
    }

    private static final ScheduledExecutorService EXECUTOR = new ScheduledThreadPoolExecutor(5,
            new BasicThreadFactory.Builder().namingPattern("delay-schedule-pool-%d").daemon(true).build());


    /**
     * 延时执行run
     *
     * @param runnable
     * @param delay
     */
    public static ScheduledFuture<?> delay(Runnable runnable, long delay) {
        return EXECUTOR.schedule(runnable, delay, TimeUnit.SECONDS);
    }

    /**
     * 延时5s执行
     *
     * @param runnable
     */
    public static ScheduledFuture<?> delay(Runnable runnable) {
        return delay(runnable, 5);
    }

    /**
     * 可获取返回值的延迟执行
     *
     * @param callable
     * @param delay
     * @param <V>      返回值类型
     * @return
     */
    public static <V> ScheduledFuture<V> delay(Callable<V> callable, long delay) {
        return EXECUTOR.schedule(callable, delay, TimeUnit.SECONDS);
    }

    /**
     * 可获取返回值的延迟5s执行
     *
     * @param callable
     * @param <V>      返回值类型
     * @return
     */
    public static <V> ScheduledFuture<V> delay(Callable<V> callable) {
        return delay(callable, 5);
    }

    /**
     * 延时执行, 返回值为null时重试, 最大重试retryLimit次
     *
     * @param callable   延迟执行任务
     * @param delay      延迟时间(s)
     * @param retryLimit 最大重试次数
     */
    public static <V> void delayRetry(final Callable<V> callable, final long delay, final int retryLimit) {
        delay(() -> {
            try {
                RetryUtils.retryOnException(() -> {
                    final ScheduledFuture<V> future = delay(callable, delay);
                    V result = future.get();
                    if (result == null) {
                        throw new RuntimeException("延迟获取数据失败");
                    }
                    return result;
                }, retryLimit);
            } catch (Throwable throwable) {
                log.error(StringUtils.format("延迟{}s, 重试{}次, 获取数据失败", delay, retryLimit), throwable);
            }
        }, 0);
    }

    /**
     * 延时执行, 返回值为null时重试, 最大重试3次
     *
     * @param callable 延迟执行任务
     * @param delay    延迟时间(s)
     */
    public static <V> void delayRetry3(final Callable<V> callable, final long delay) {
        delayRetry(callable, delay, 3);
    }

    /**
     * 延时5s执行, 返回值为null时重试, 最大重试3次
     *
     * @param callable 延迟执行任务
     */
    public static <V> void delay5Retry3(final Callable<V> callable) {
        delayRetry(callable, 5, 3);
    }

    /**
     * 延时30s执行, 返回值为null时重试, 最大重试3次
     *
     * @param callable 延迟执行任务
     */
    public static <V> void delay30Retry3(final Callable<V> callable) {
        delayRetry(callable, 30, 3);
    }

}
